home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / INFO / PCCDEMO.ZIP / COMP1.EXE / MODEXLIB.C < prev    next >
C/C++ Source or Header  |  1993-12-20  |  8KB  |  337 lines

  1. /*
  2.  * LIB.C v1.1
  3.  *
  4.  * by Robert Schmidt
  5.  * (C)1993 Ztiff Zox Softwear
  6.  *
  7.  * Simple graphics library to accompany the article
  8.  *                    INTRODUCTION TO MODE X.
  9.  * This library provides the basic functions for initializing and using
  10.  * unchained (planar) 256-color VGA modes.  Currently supported are:
  11.  *
  12.  *    - 320x200
  13.  *    - 320x240
  14.  *
  15.  * Functions are provided for:
  16.  *
  17.  *    - initializing one of the available modes
  18.  *    - setting the start address of the VGA refresh data
  19.  *    - setting active and visible display pages
  20.  *    - writing and reading a single pixel to/from video memory
  21.  *
  22.  * The library is provided as a demonstration only, and is not claimed
  23.  * to be particularly efficient or suited for any purpose.  It has only
  24.  * been tested with Borland C++ 3.1 by the author.  Comments on success
  25.  * or disaster with other compilers are welcome.
  26.  *
  27.  * This file is public domain.  Do with it whatever you'd like, but
  28.  * please don't distribute it without the article.
  29.  */
  30.  
  31. /*
  32.  * We 'require' a large data model simply to get rid of explicit 'far'
  33.  * pointers and compiler specific '_fmemset()' functions and the likes.
  34.  */
  35.  
  36. #if !defined(__COMPACT__)
  37. # if !defined(__LARGE__)
  38. #  if !defined(__HUGE__)
  39. #   error Large data model required!
  40. #  endif
  41. # endif
  42. #endif
  43.  
  44. #include <dos.h>
  45. #include <mem.h>
  46.  
  47. /*
  48.  * Comment out the following #define if you don't want the testing main()
  49.  * to be included. 
  50.  */
  51.  
  52. #define TESTING
  53.  
  54. /*
  55.  * Uncomment the following #define if you want the library to support
  56.  * monochrome _instead of_ color operations.  This has not been tested.
  57.  */
  58.  
  59. /* #define VGA_MONO */
  60.  
  61. #ifndef VGA_MONO
  62. #define CRTC_ADDR    0x3d4    /* Base port of the CRT Controller (color) */
  63. #else
  64. #define CRTC_ADDR    0x3b4    /* Base port of the CRT Controller (mono) */
  65. #endif
  66.  
  67. #define SEQU_ADDR    0x3c4    /* Base port of the Sequencer */
  68. #define GRAC_ADDR    0x3ce    /* Base port of the Graphics Controller */
  69.  
  70. typedef unsigned char UCHAR;
  71.  
  72. /* 
  73.  * Make a far pointer to the VGA graphics buffer segment.  Your compiler
  74.  * might not have the MK_FP macro, but you'll figure something out. 
  75.  */
  76.  
  77. UCHAR *vga = (UCHAR *) MK_FP(0xA000, 0);
  78.  
  79. /* 
  80.  * width and height should specify the mode dimensions.  widthBytes
  81.  * specify the width of a line in addressable bytes. 
  82.  */
  83.  
  84. unsigned width, height, widthBytes;
  85.  
  86. /* 
  87.  * actStart specifies the start of the page being accessed by
  88.  * drawing operations.  visStart specifies the contents of the Screen
  89.  * Start register, i.e. the start of the visible page.
  90.  */
  91.  
  92. unsigned actStart, visStart;
  93.  
  94. /*
  95.  * set320x200x256_X()
  96.  *    sets mode 13h, then turns it into an unchained (planar), 4-page
  97.  *    320x200x256 mode.
  98.  */
  99.  
  100. void set320x200x256_X(void)
  101.     {
  102.  
  103.     union REGS r;
  104.  
  105.     /* Set VGA BIOS mode 13h: */
  106.  
  107.     r.x.ax = 0x0013;
  108.     int86(0x10, &r, &r);
  109.  
  110.     /* Turn off the Chain-4 bit (bit 3 at index 4, port 0x3c4): */
  111.  
  112.     outport(SEQU_ADDR, 0x0604);
  113.  
  114.     /* Turn off word mode, by setting the Mode Control register
  115.        of the CRT Controller (index 0x17, port 0x3d4): */
  116.  
  117.     outport(CRTC_ADDR, 0xE317);
  118.  
  119.     /* Turn off doubleword mode, by setting the Underline Location
  120.        register (index 0x14, port 0x3d4): */
  121.  
  122.     outport(CRTC_ADDR, 0x0014);
  123.  
  124.     /* Clear entire video memory, by selecting all four planes, then
  125.        writing 0 to entire segment. */
  126.  
  127.     outport(SEQU_ADDR, 0x0F02);
  128.     memset(vga+1, 0, 0xffff); /* stupid size_t exactly 1 too small */
  129.     vga[0] = 0;
  130.  
  131.     /* Update the global variables to reflect dimensions of this
  132.        mode.  This is needed by most future drawing operations. */
  133.  
  134.     width   = 320;
  135.     height    = 200;
  136.  
  137.     /* Each byte addresses four pixels, so the width of a scan line
  138.        in *bytes* is one fourth of the number of pixels on a line. */
  139.  
  140.     widthBytes = width / 4;
  141.  
  142.     /* By default we want screen refreshing and drawing operations
  143.        to be based at offset 0 in the video segment. */
  144.  
  145.     actStart = visStart = 0;
  146.  
  147.     }
  148.  
  149. /*
  150.  * setActiveStart() tells our graphics operations which address in video
  151.  * memory should be considered the top left corner.
  152.  */
  153.  
  154. void setActiveStart(unsigned offset)
  155.     {
  156.     actStart = offset;
  157.     }
  158.  
  159. /*
  160.  * setVisibleStart() tells the VGA from which byte to fetch the first
  161.  * pixel when starting refresh at the top of the screen.  This version
  162.  * won't look very well in time critical situations (games for
  163.  * instance) as the register outputs are not synchronized with the
  164.  * screen refresh.  This refresh might start when the high byte is
  165.  * set, but before the low byte is set, which produces a bad flicker.
  166.  */
  167.  
  168. void setVisibleStart(unsigned offset)
  169.     {
  170.     visStart = offset;
  171.     outport(CRTC_ADDR, 0x0C);        /* set high byte */
  172.     outport(CRTC_ADDR+1, visStart >> 8);
  173.     outport(CRTC_ADDR, 0x0D);        /* set low byte */
  174.     outport(CRTC_ADDR+1, visStart & 0xff);
  175.     }
  176.  
  177. /*
  178.  * setXXXPage() sets the specified page by multiplying the page number
  179.  * with the size of one page at the current resolution, then handing the
  180.  * resulting offset value over to the corresponding setXXXStart()
  181.  * function.  The first page is number 0.
  182.  */
  183.  
  184. void setActivePage(int page)
  185.     {
  186.     setActiveStart(page * widthBytes * height);
  187.     }
  188.  
  189. void setVisiblePage(int page)
  190.     {
  191.     setVisibleStart(page * widthBytes * height);
  192.     }
  193.  
  194. void putPixel_X(int x, int y, UCHAR color)
  195.     {
  196.  
  197.     /* Each address accesses four neighboring pixels, so set
  198.        Write Plane Enable according to which pixel we want
  199.        to modify.  The plane is determined by the two least
  200.        significant bits of the x-coordinate: */
  201.  
  202.     outportb(0x3c4, 0x02);
  203.     outportb(0x3c5, 0x01 << (x & 3));
  204.  
  205.     /* The offset of the pixel into the video segment is
  206.        offset = (width * y + x) / 4, and write the given
  207.        color to the plane we selected above.  Heed the active
  208.        page start selection. */
  209.  
  210.     vga[(unsigned)(widthBytes * y) + (x / 4) + actStart] = color;
  211.  
  212.     }
  213.  
  214. UCHAR getPixel_X(int x, int y)
  215.     {
  216.  
  217.     /* Select the plane from which we must read the pixel color: */
  218.  
  219.     outport(GRAC_ADDR, 0x04);
  220.     outport(GRAC_ADDR+1, x & 3);
  221.  
  222.     return vga[(unsigned)(widthBytes * y) + (x / 4) + actStart];
  223.  
  224.     }
  225.  
  226. void set320x240x256_X(void)
  227.     {
  228.  
  229.     /* Set the unchained version of mode 13h: */
  230.  
  231.     set320x200x256_X();
  232.  
  233.     /* Modify the vertical sync polarity bits in the Misc. Output
  234.        Register to achieve square aspect ratio: */
  235.  
  236.     outportb(0x3C2, 0xE7);
  237.  
  238.     /* Modify the vertical timing registers to reflect the increased
  239.        vertical resolution, and to center the image as good as
  240.        possible: */
  241.  
  242.     outport(0x3D4, 0x2C11);        /* turn off write protect */
  243.     outport(0x3D4, 0x0D06);        /* vertical total */
  244.     outport(0x3D4, 0x3E07);        /* overflow register */
  245.     outport(0x3D4, 0xEA10);        /* vertical retrace start */
  246.     outport(0x3D4, 0xAC11);        /* vertical retrace end AND wr.prot */
  247.     outport(0x3D4, 0xDF12);        /* vertical display enable end */
  248.     outport(0x3D4, 0xE715);        /* start vertical blanking */
  249.     outport(0x3D4, 0x0616);        /* end vertical blanking */
  250.  
  251.     /* Update mode info, so future operations are aware of the
  252.        resolution */
  253.  
  254.     height = 240;
  255.  
  256.     }
  257.  
  258.  
  259. #ifdef TESTING
  260.  
  261. #include <stdio.h>
  262. #include <conio.h>
  263.  
  264. void set80x25(void)
  265.     {
  266.     union REGS r;
  267.     r.x.ax = 0x0003;
  268.     int86(0x10, &r, &r);
  269.     }
  270.  
  271. void doTest(void)
  272.     {
  273.     int p, x, y, pages;
  274.  
  275.     /* This is the way to calculate the number of pages available. */
  276.  
  277.     pages = 65536L/(widthBytes*height);
  278.  
  279.     for (p = 0; p < pages; ++p)
  280.         {
  281.         setActivePage(p);
  282.  
  283.         /* On each page draw a single colored border, and dump the palette
  284.            onto a small square about the middle of the page. */
  285.  
  286.         for (x = 0; x <= width; ++x)
  287.             {
  288.             putPixel_X(x, 0, p+1);
  289.             putPixel_X(x, height-1, p+1);
  290.             }
  291.  
  292.         for (y = 0; y <= height; ++y)
  293.             {
  294.             putPixel_X(0, y, p+1);
  295.             putPixel_X(width-1, y, p+1);
  296.             }
  297.  
  298.         for (x = 0; x < 16; ++x)
  299.             for (y = 0; y < 16; ++y)
  300.                 putPixel_X(x+(p+3)*16, y+(p+3)*16, x + y*16);
  301.  
  302.         }
  303.  
  304.     /* Each pages will now contain a different image.  Let the user cycle
  305.        through all the pages by pressing a key. */
  306.  
  307.     for (p = 0; p < pages; ++p)
  308.         {
  309.         setVisiblePage(p);
  310.         getch();
  311.         }
  312.  
  313.     }
  314.  
  315.  
  316. int main(void)
  317.     {
  318.     puts("First, have a look at the 320x200 mode, with 4 pages...");
  319.     getch();
  320.  
  321.     set320x200x256_X();
  322.     doTest();
  323.  
  324.     set80x25();
  325.     puts("Then, check out Mode X, 320x240 with 3 (and a half) pages...");
  326.     getch();
  327.  
  328.     set320x240x256_X();
  329.     doTest();
  330.  
  331.     set80x25();
  332.     puts("Where to next?  It's your move!");
  333.     return 0;
  334.     }
  335.  
  336. #endif
  337.